package com.atguigu.spzx.order.service.Impl;

import cn.hutool.core.util.IdUtil;
import com.atguigu.spzx.cart.client.CartClient;
import com.atguigu.spzx.common.Interceptor.SpzxUserInfoInterceptor;
import com.atguigu.spzx.common.exception.GuiguException;
import com.atguigu.spzx.feign.product.ProductFeignClient;
import com.atguigu.spzx.model.dto.order.OrderDto;
import com.atguigu.spzx.model.entity.h5.CartInfo;
import com.atguigu.spzx.model.entity.order.OrderInfo;
import com.atguigu.spzx.model.entity.order.OrderItem;
import com.atguigu.spzx.model.entity.order.OrderLog;
import com.atguigu.spzx.model.entity.product.ProductSku;
import com.atguigu.spzx.model.entity.user.UserAddress;
import com.atguigu.spzx.model.entity.user.UserInfo;
import com.atguigu.spzx.model.vo.common.Result;
import com.atguigu.spzx.model.vo.common.ResultCodeEnum;
import com.atguigu.spzx.model.vo.order.OrderTradeVo;
import com.atguigu.spzx.order.mapper.OrderInfoMapper;
import com.atguigu.spzx.order.mapper.OrderItemMapper;
import com.atguigu.spzx.order.mapper.OrderLogMapper;
import com.atguigu.spzx.order.service.OrderService;
import com.atguigu.spzx.user.client.UserClient;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.TimeoutUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author syh
 * @create 2023-09-03 16:34
 */
@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    CartClient cartClient;
    @Resource
    ProductFeignClient productFeignClient;
    @Resource
    UserClient userClient;
    @Resource
    OrderInfoMapper orderInfoMapper;
    @Resource
    OrderItemMapper orderItemMapper;
    @Resource
    OrderLogMapper orderLogMapper;
    @Resource
    StringRedisTemplate stringRedisTemplate;



    @Override
    public OrderTradeVo trade() {
        Result<List<CartInfo>> result = cartClient.getAllCheckedCartInfo();

        List<CartInfo> cartInfoList = result.getData();
        if(CollectionUtils.isEmpty(cartInfoList)){
            throw new GuiguException(ResultCodeEnum.UNKNOW_ERROR);
        }
        //总金额
        //使用streamApi计算，每个购物项需要计算 数量*单价的结果，然后累加
        BigDecimal totalAmount = cartInfoList.stream()
                .map(cartInfo -> cartInfo.getCartPrice().multiply(new BigDecimal(cartInfo.getSkuNum())))
                .reduce((a, b) -> a.add(b)).get();


        //购物项和订单项一一对应   购物车和订单对应
        //将购物项转为订单项
        List<OrderItem> orderItems = cartInfoList.stream().map(cartInfo -> {
            OrderItem orderItem = new OrderItem();
            orderItem.setSkuName(cartInfo.getSkuName());
            orderItem.setSkuId(cartInfo.getSkuId());
            orderItem.setSkuNum(cartInfo.getSkuNum().intValue());
            orderItem.setThumbImg(cartInfo.getImgUrl());
            orderItem.setSkuPrice(cartInfo.getCartPrice());
            return orderItem;
        }).collect(Collectors.toList());

        OrderTradeVo orderTradeVo = new OrderTradeVo();
        orderTradeVo.setTotalAmount(totalAmount);
        orderTradeVo.setOrderItemList(orderItems);
        //保存唯一的标识到redis中：将来订单确认页 提交订单时 可以防止重复提交
//        UserInfo userInfo = SpzxUserInfoInterceptor.THREAD_LOCAL.get();
//        stringRedisTemplate.opsForValue().set("order:trade"+userInfo.getId(),"1", 5, TimeUnit.MINUTES);
        //下单不操作数据库的订单相关的表
        return orderTradeVo;
    }

    @Override
    public Long submitOrder(OrderDto orderDto) {
        UserInfo userInfo = SpzxUserInfoInterceptor.THREAD_LOCAL.get();
//////        //判断是否是重复提交的请求
//        Boolean hasKey = stringRedisTemplate.hasKey("order:trade:" + userInfo.getId());
//        if(!hasKey){
//            //提交订单的请求重复提交了，或者是非法请求  或者是 订单页数据过期超时
//            //返回异常后 前端可以根据异常状态码  刷新页面
//            throw new GuiguException(ResultCodeEnum.UNKNOW_ERROR);
//        }
//        stringRedisTemplate.delete("order:trade:" + userInfo.getId());
        //1.接收前端提交的下单参数
        BigDecimal feightFee=orderDto.getFeightFee();
        List<OrderItem> orderItemList = orderDto.getOrderItemList();
        String remark = orderDto.getRemark();
        Long userAddressId = orderDto.getUserAddressId();
        if (CollectionUtils.isEmpty(orderItemList)||userAddressId==null){
            throw new GuiguException(ResultCodeEnum.ORDER_CREATE_AUTH);
        }
        List<ProductSku> productSkus = productFeignClient.findProductSkus(orderItemList).getData();
        if (CollectionUtils.isEmpty(productSkus)||productSkus.size()!=orderItemList.size()){
            //验库存失败
            throw new GuiguException(ResultCodeEnum.ORDER_STOCK_AUTH);
        }
        //保存订单，保存订单项
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setUserId(userInfo.getId());
        orderInfo.setNickName(userInfo.getNickName());
        //订单编号：使用hutool工具类生成雪花算法的19位长度的id
        //  使用时间戳：并发时会产生一样的NO
        String orderNo = IdUtil.createSnowflake(1, 1).nextIdStr();
        orderInfo.setOrderNo(orderNo);
        //计算订单总金额
        BigDecimal totalAmount = orderItemList.stream().map(orderItem ->
                        orderItem.getSkuPrice().multiply(new BigDecimal(orderItem.getSkuNum())))
                .reduce((a, b) -> a.add(b))
                .get();
        orderInfo.setTotalAmount(totalAmount);
        //优惠券金额
        orderInfo.setCouponAmount(new BigDecimal(0));
        //商品市场价
        Map<Long, BigDecimal> marketPriceMap = productSkus.stream().collect(Collectors.toMap(ProductSku::getId, ProductSku::getMarketPrice));
        BigDecimal originalTotalAmount = orderItemList.stream().map(orderItem -> {
                    BigDecimal marketPrice = marketPriceMap.get(orderItem.getSkuId());
                    return new BigDecimal(orderItem.getSkuNum()).multiply(marketPrice);
                })
                .reduce((a, b) -> a.add(b))
                .get();

        orderInfo.setOriginalTotalAmount(originalTotalAmount);

        orderInfo.setFeightFee(feightFee);
        //支付方式：
        orderInfo.setPayType(2);
        //订单状态： 0表示待付款
        orderInfo.setOrderStatus(0);
        orderInfo.setRemark(remark);
        orderInfo.setCreateTime(new Date());
        orderInfo.setUpdateTime(new Date());

        //查询地址信息
        UserAddress userAddress = userClient.findUserAddressById(userAddressId).getData();

        orderInfo.setReceiverTagName(userAddress.getTagName());
        orderInfo.setReceiverAddress(userAddress.getFullAddress());
        orderInfo.setReceiverProvince(userAddress.getProvinceCode());
        orderInfo.setReceiverCity(userAddress.getCityCode());
        orderInfo.setReceiverDistrict(userAddress.getDistrictCode());
        orderInfo.setReceiverPhone(userAddress.getPhone());
        orderInfo.setReceiverName(userAddress.getName());

        orderInfoMapper.save(orderInfo);
        //     订单项： 需要关联订单的id
        //为订单项设置数据
        orderItemList.forEach(orderItem -> {
            //绑定订单id(新增订单时一定要返回id)
            orderItem.setOrderId(orderInfo.getId());
            orderItem.setCreateTime(new Date());
            orderItem.setUpdateTime(new Date());
            orderItemMapper.save(orderItem);
        });
        //4、保存订单创建的日志
        OrderLog orderLog = new OrderLog();
        orderLog.setOrderId(orderInfo.getId());
        orderLog.setProcessStatus(orderInfo.getOrderStatus());
        orderLog.setOperateUser(userInfo.getUsername());
        orderLog.setNote("创建订单");
        orderLog.setCreateTime(new Date());
        orderLog.setUpdateTime(new Date());
        orderLogMapper.save(orderLog);
        //5、删除订单对应的购物项
        // 只要删除下单用户购物车中选中的购物项
        cartClient.deleteCheckedCartInfo();


        //返回订单id
        return orderInfo.getId();
    }
//    @Override
    public OrderInfo findOrderById(Long id) {
        //查询订单项和它的订单详情列表
        return orderInfoMapper.findOrderById(id);
    }

    @Override
    public OrderTradeVo buy(Long skuId) {
        //先查询商品数据
        ProductSku productSku = productFeignClient.findSkuBySkuId(skuId).getData();
        OrderTradeVo orderTradeVo = new OrderTradeVo();
        OrderItem orderItem = new OrderItem();
        orderItem.setSkuName(productSku.getSkuName());
        orderItem.setSkuId(productSku.getId());
        orderItem.setSkuNum(1);
        orderItem.setThumbImg(productSku.getThumbImg());
        orderItem.setSkuPrice(productSku.getSalePrice());


        orderTradeVo.setTotalAmount(productSku.getSalePrice());
        orderTradeVo.setOrderItemList(Arrays.asList(orderItem));
        //保存唯一的标识到redis中：将来订单确认页 提交订单时 可以防止重复提交
        UserInfo userInfo = SpzxUserInfoInterceptor.THREAD_LOCAL.get();
        stringRedisTemplate.opsForValue().set("order:trade:"+userInfo.getId(),
                "1" , 5, TimeUnit.MINUTES);
        //下单不操作数据库的订单相关的表
        return orderTradeVo;
    }

    @Override
    public PageInfo<OrderInfo> page(Integer page, Integer limit, Integer orderStatus) {
        PageHelper.startPage(page,limit);
        List<OrderInfo> orderInfos = orderInfoMapper.findOrderPageByStatus(orderStatus);
        return new PageInfo<>(orderInfos);
    }

    @Override
    public OrderInfo findOrderByOrderNo(Long orderNo) {
        return orderInfoMapper.findOrderByOrderNo(orderNo);
    }

    @Override
    public void updateOrderByOrderNo(Long orderNo) {
        orderInfoMapper.updateOrderByOrderNo(orderNo);
    }
}
